#ifndef GEO_MF_ONLINE_CC
#define GEO_MF_ONLINE_CC
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include "def.hpp"
#include "utils.hpp"
#include "topicmodel_geo_abstract.hpp"

class GeoMFOnline:public GeoTopicModel{
protected:
  double* phi_0; // background language model for the whole corpus
  GeoTerms phi_geo;
  vector<int> doc_n;
  double** pi; // topic matrix
  double** phi_norm;  
  double* theta_0; // background topic distribution
  double** theta_geo; // background topic distribution for each geo location
  double** theta_user; // background topic distribution for each user
  int* d_k;
  vector<map<int,int> > d_r_k;
  vector<map<int,int> > d_u_k;
  int* d_r;
  int* d_u;
  

  int* doc_topic_z; // topic assignment for each document

  int N;
  int switch_label;
  double* theta_norm_buffer; // used for calculating theta norm
  double* phi_norm_buffer; // used for calculating phi norm
  double lowerbound;
  double learning_rate;
  double reg;
  int K; // parameter for L1 regularization by using Truncated Gradient method
  double g; // parameter for controling the sparsity
  ofstream file_output;
public:
  GeoMFOnline();
  virtual void Inference();
  virtual void Prediction();
  virtual double Likelihood();
  virtual int ReadDOCS();
  virtual int GetDocuments(int); // this indicate how documents are read through into the model
  virtual int SaveModel();

private:
  int Single_E_Step(int);
  int Single_M_Step();
  int Single_M_Step_L1();
};

int GeoMFOnline::SaveModel(){
  ofstream outFile;
  string model_file = PuzaDEF::Instance()->output_file_name + ".pi";
  outFile.open(model_file.c_str());
  for (int i=0; i<PuzaDEF::Instance()->TERM_NUM; i++){
    outFile << i << "\t";
    for (int k=0; k<PuzaDEF::Instance()->TOPIC_NUM; k++){
      outFile << k << ":" << pi[k][i] << " ";
    }
    outFile << endl;
  }
  outFile.flush();
  outFile.close();

  model_file = PuzaDEF::Instance()->output_file_name + ".phi0";
  outFile.open(model_file.c_str());
  for (int i=0; i<PuzaDEF::Instance()->TERM_NUM; i++){
    outFile << i << ":" << phi_0[i] << " " << endl;;
  }
  outFile.flush();
  outFile.close();

  model_file = PuzaDEF::Instance()->output_file_name + ".theta0";
  outFile.open(model_file.c_str());
  for (int k=0; k<PuzaDEF::Instance()->TOPIC_NUM; k++){
    outFile << k << ":" << theta_0[k] << " " << endl;;
  }
  outFile.flush();
  outFile.close();

  model_file = PuzaDEF::Instance()->output_file_name + ".theta_geo";
  outFile.open(model_file.c_str());
  for(int i=0; i < PuzaDEF::Instance()->GEO_REGION_NUM; i++){
    outFile << i << "\n\t";
    for (int k=0; k<PuzaDEF::Instance()->TOPIC_NUM; k++){
      outFile << k << ":" << theta_geo[i][k] << " " ;
    }
    outFile << endl;
  }
  outFile.flush();
  outFile.close();

  model_file = PuzaDEF::Instance()->output_file_name + ".theta_user";
  outFile.open(model_file.c_str());
  for(int i=0; i < PuzaDEF::Instance()->GEO_USER_NUM; i++){
    outFile << i << "\n\t";
    for (int k=0; k<PuzaDEF::Instance()->TOPIC_NUM; k++){
      outFile << k << ":" << theta_user[i][k] << " " ;
    }
    outFile << endl;
  }
  outFile.flush();
  outFile.close();

  model_file = PuzaDEF::Instance()->output_file_name + ".phi_geo";
  outFile.open(model_file.c_str());
  for(int r=0; r<PuzaDEF::Instance()->GEO_REGION_NUM; r++){
    outFile << geo_mapping[r] << "\t";
    for(map<int,double>::iterator iter = phi_geo[r].begin(); iter != phi_geo[r].end(); iter++){
      outFile << (*iter).first << ":" << (*iter).second << " ";
    }
    outFile << endl;
  }
  outFile.flush();
  outFile.close();

  model_file = PuzaDEF::Instance()->output_file_name + ".z";
  outFile.open(model_file.c_str());
  for(unsigned int d = 0; d < TM_DOCS.size(); d++){
    int k = doc_topic_z[d];
    int region = doc_geo_stamp[d];
    int user = doc_user_stamp[d];
    outFile << d << "\t" << region << "\t" << user << "\t" << k << endl;
  }
  outFile.flush();
  outFile.close();
  return 0;
}

GeoMFOnline::GeoMFOnline(){
  allocate_memory<double>(pi, PuzaDEF::Instance()->TOPIC_NUM,PuzaDEF::Instance()->TERM_NUM);
  allocate_memory<double>(theta_geo, PuzaDEF::Instance()->GEO_REGION_NUM,PuzaDEF::Instance()->TOPIC_NUM);
  allocate_memory<double>(theta_user, PuzaDEF::Instance()->GEO_USER_NUM,PuzaDEF::Instance()->TOPIC_NUM);
  allocate_memory<double>(phi_norm, PuzaDEF::Instance()->GEO_REGION_NUM,PuzaDEF::Instance()->TOPIC_NUM);

  phi_0 = new double[PuzaDEF::Instance()->TERM_NUM];
  theta_0 = new double[PuzaDEF::Instance()->TOPIC_NUM];
  doc_topic_z = new int[PuzaDEF::Instance()->DOC_NUM];
  phi_norm_buffer = new double[PuzaDEF::Instance()->TERM_NUM];
  theta_norm_buffer = new double[PuzaDEF::Instance()->TOPIC_NUM];

  phi_geo.resize(PuzaDEF::Instance()->GEO_REGION_NUM);
  d_r_k.resize(PuzaDEF::Instance()->GEO_REGION_NUM);
  d_u_k.resize(PuzaDEF::Instance()->GEO_USER_NUM);
  d_k = new int[PuzaDEF::Instance()->TOPIC_NUM];
  d_r = new int[PuzaDEF::Instance()->GEO_REGION_NUM];
  d_u = new int[PuzaDEF::Instance()->GEO_USER_NUM];
  
  // some initialization
  for(int k=0; k < PuzaDEF::Instance()->TOPIC_NUM; k ++){
    for(int i=0; i < PuzaDEF::Instance()->TERM_NUM; i++){
      pi[k][i] = 0.0;
    }
    theta_0[k] = 0.0;
    d_k[k] = 0;
  }

  for(int r=0; r < PuzaDEF::Instance()->GEO_REGION_NUM; r ++){
    for(int k=0; k < PuzaDEF::Instance()->TOPIC_NUM; k++){
      theta_geo[r][k] = 0.0;
    }
    d_r[r] = 0;
  }

  for(int u=0; u < PuzaDEF::Instance()->GEO_USER_NUM; u ++){
    for(int k=0; k < PuzaDEF::Instance()->TOPIC_NUM; k++){
      theta_user[u][k] = 0.0;
    }
    d_u[u] = 0;
  }

  for(int i=0; i < PuzaDEF::Instance()->TERM_NUM; i++){
    phi_0[i] = 0.0;
  }

  learning_rate = PuzaDEF::Instance()->GEO_LEARNING_RATE;
  reg = PuzaDEF::Instance()->GEO_REG;
  K = PuzaDEF::Instance()->GEO_REG_L1_K;
  g = PuzaDEF::Instance()->GEO_REG_L1_G;
}

int GeoMFOnline::Single_E_Step(int d){
  // perform gibbs sampling for each document
  double* p = new double[PuzaDEF::Instance()->TOPIC_NUM];  
  int region = doc_geo_stamp[d];
  int user = doc_user_stamp[d];
  int new_topic = 0;
  double u = 0.0;
  double theta_norm = 0.0;
  TermList current_list = TM_DOCS[d];
  int term_count = current_list.size();

  // minus stats
  for(int k =0; k < PuzaDEF::Instance()->TOPIC_NUM;k++){
    theta_norm_buffer[k] = theta_0[k] + theta_user[user][k] + theta_geo[region][k];
  }
  theta_norm = log_sum_array(theta_norm_buffer,PuzaDEF::Instance()->TOPIC_NUM); // calculate theta normalization part

  for(int k =0; k < PuzaDEF::Instance()->TOPIC_NUM; k++){
    p[k] = theta_0[k] + theta_geo[region][k] + theta_user[user][k];
    for (int j=0;j < term_count; j++){
      int term_id = current_list[j].term_id;
      int count = current_list[j].term_stat;
      p[k] = p[k] + count * (phi_0[term_id] + pi[k][term_id] - phi_norm[region][k]); // term level
    }
    p[k] = p[k] - theta_norm;
  }


  d_r_k[region][doc_topic_z[d]] = d_r_k[region][doc_topic_z[d]] - 1;
  if(d_r_k[region][doc_topic_z[d]] == 0)
    d_r_k[region].erase(doc_topic_z[d]);
  d_k[doc_topic_z[d]] = d_k[doc_topic_z[d]] - 1;
  d_u_k[user][doc_topic_z[d]] = d_u_k[user][doc_topic_z[d]] - 1;
  if(d_u_k[user][doc_topic_z[d]] == 0)
    d_u_k[user].erase(doc_topic_z[d]);

  // convert back to probabilities and normalize
  p[0] = exp(p[0]);
  for(int k=1; k < PuzaDEF::Instance()->TOPIC_NUM; k++){
    p[k] = exp(p[k]) + p[k-1];
  }

  // sampling from log space of uniform distribution
  u = gsl_rng_uniform(PuzaDEF::Instance()->gBaseRand) * p[PuzaDEF::Instance()->TOPIC_NUM-1];
  for(new_topic = 0; new_topic < PuzaDEF::Instance()->TOPIC_NUM; new_topic++){
    if (u < p[new_topic])
      break;
  }

  d_r_k[region][new_topic] = d_r_k[region][new_topic] + 1;
  d_k[new_topic] = d_k[new_topic] + 1;
  d_u_k[user][new_topic] = d_u_k[user][new_topic] + 1;

  if(new_topic != doc_topic_z[d])
    switch_label ++;

  doc_topic_z[d] = new_topic;
  delete p;
  return 0;
}

int GeoMFOnline::Single_M_Step(){
  int m_iter = 0;
  while(1){
    for(unsigned int d = 0; d < TM_DOCS.size(); d++){
      int k = doc_topic_z[d];
      int region = doc_geo_stamp[d];
      int user = doc_user_stamp[d];
      TermList current_list = TM_DOCS[d];
      int term_count = current_list.size();
      
      for (int j=0;j < term_count; j++){
	int term_id = current_list[j].term_id;
	int count = current_list[j].term_stat;
	double gradient_w = count -   doc_n[d] * exp(phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id] - phi_norm[region][k]);
	double pi_minus = phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id];
	pi[k][term_id] = pi[k][term_id] + learning_rate * gradient_w; // update matrix pi
	phi_geo[region][term_id] = phi_geo[region][term_id] + learning_rate * gradient_w; // update phi geo
	double pi_addition = phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id];
	phi_norm[region][k] = log_sub(phi_norm[region][k],pi_minus); // important! no minus sign
	phi_norm[region][k] = log_sum(phi_norm[region][k],pi_addition);
      }
      
      for(int j=0; j < PuzaDEF::Instance()->TOPIC_NUM; j++){
	theta_norm_buffer[j] = theta_0[j] + theta_geo[region][j] + theta_user[user][j];
      }
      double theta_norm = log_sum_array(theta_norm_buffer,PuzaDEF::Instance()->TOPIC_NUM);
      
      double gradient_theta_k = 1 - (TM_DOCS.size() / float(d_k[k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k] - theta_norm);
      theta_0[k] = theta_0[k] + learning_rate * gradient_theta_k;
      gradient_theta_k = 1 - (d_r[region] / float(d_r_k[region][k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k] - theta_norm);
      theta_geo[region][k] = theta_geo[region][k] + learning_rate * gradient_theta_k;
      gradient_theta_k = 1 - (d_u[user] / float(d_u_k[user][k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k]- theta_norm);
      theta_user[user][k] = theta_user[user][k] + learning_rate * gradient_theta_k;
    }
    m_iter++;
    //    if(m_iter >= 50)
    break;
  }
  return 0;
}

int GeoMFOnline::Single_M_Step_L1(){
  int m_iter = 0;
  while(1){
    for(unsigned int d = 0; d < TM_DOCS.size(); d++){
      int k = doc_topic_z[d];
      int region = doc_geo_stamp[d];
      int user = doc_user_stamp[d];
      TermList current_list = TM_DOCS[d];
      int term_count = current_list.size();
      
      if(d % K != 0 ){
	for (int j=0;j < term_count; j++){
	  int term_id = current_list[j].term_id;
	  int count = current_list[j].term_stat;
	  double gradient_w = count -   doc_n[d] * exp(phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id] - phi_norm[region][k]);
	  double pi_minus = phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id];
	  pi[k][term_id] = pi[k][term_id] + learning_rate * gradient_w; // update matrix pi
	  phi_geo[region][term_id] = phi_geo[region][term_id] + learning_rate * gradient_w; // update phi geo
	  double pi_addition = phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id];
	  phi_norm[region][k] = log_sub(phi_norm[region][k],pi_minus); // important! no minus sign
	  phi_norm[region][k] = log_sum(phi_norm[region][k],pi_addition);
	}
	
	for(int j=0; j < PuzaDEF::Instance()->TOPIC_NUM; j++){
	  theta_norm_buffer[j] = theta_0[j] + theta_geo[region][j] + theta_user[user][j];
	}
	double theta_norm = log_sum_array(theta_norm_buffer,PuzaDEF::Instance()->TOPIC_NUM);
	
	double gradient_theta_k = 1 - (TM_DOCS.size() / float(d_k[k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k] - theta_norm);
	theta_0[k] = theta_0[k] + learning_rate * gradient_theta_k;
	gradient_theta_k = 1 - (d_r[region] / float(d_r_k[region][k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k] - theta_norm);
	theta_geo[region][k] = theta_geo[region][k] + learning_rate * gradient_theta_k;
	gradient_theta_k = 1 - (d_u[user] / float(d_u_k[user][k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k]- theta_norm);
	theta_user[user][k] = theta_user[user][k] + learning_rate * gradient_theta_k;
      }
      else{
	for (int j=0;j < term_count; j++){
	  int term_id = current_list[j].term_id;
	  int count = current_list[j].term_stat;
	  double gradient_w = count -   doc_n[d] * exp(phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id] - phi_norm[region][k]);
	  double pi_minus = phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id];
	  pi[k][term_id] = Trunc(pi[k][term_id] + learning_rate * gradient_w, learning_rate * g * K); // update matrix pi
	  phi_geo[region][term_id] = Trunc(phi_geo[region][term_id] + learning_rate * gradient_w, learning_rate * g * K); // update phi geo
	  double pi_addition = phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id];
	  phi_norm[region][k] = log_sub(phi_norm[region][k],pi_minus); // important! no minus sign
	  phi_norm[region][k] = log_sum(phi_norm[region][k],pi_addition);
	}
	
	for(int j=0; j < PuzaDEF::Instance()->TOPIC_NUM; j++){
	  theta_norm_buffer[j] = theta_0[j] + theta_geo[region][j] + theta_user[user][j];
	}
	double theta_norm = log_sum_array(theta_norm_buffer,PuzaDEF::Instance()->TOPIC_NUM);
	
	double gradient_theta_k = 1 - (TM_DOCS.size() / float(d_k[k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k] - theta_norm);
	theta_0[k] = Trunc(theta_0[k] + learning_rate * gradient_theta_k, learning_rate * g * K);
	gradient_theta_k = 1 - (d_r[region] / float(d_r_k[region][k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k] - theta_norm);
	theta_geo[region][k] = Trunc(theta_geo[region][k] + learning_rate * gradient_theta_k, learning_rate * g * K);
	gradient_theta_k = 1 - (d_u[user] / float(d_u_k[user][k])) * exp(theta_0[k] + theta_geo[region][k] + theta_user[user][k]- theta_norm);
	theta_user[user][k] = Trunc(theta_user[user][k] + learning_rate * gradient_theta_k, learning_rate * g * K);
	
      }
    }
    m_iter++;
    //    if(m_iter >= 50)
    break;
  }
  return 0;
}

void GeoMFOnline::Inference(){
  PuzaLogger::Instance()->PutString("Start Inference for Geo Matrix Factorization Model");
  int ITER = 0;
  double old_lowerbound = 0;
  while(1){
    switch_label = 0;
    PuzaLogger::Instance()->PutString("Iteration "+to_string<int>(ITER,std::dec));
    for(unsigned int d=0; d < TM_DOCS.size(); d++){
      Single_E_Step(d);
    }
    PuzaLogger::Instance()->PutString("\tE-Step Finished."+to_string<int>(ITER,std::dec));
    if(PuzaDEF::Instance()->GEO_REG_TYPE == 0){
      Single_M_Step();
    }
    else{
      Single_M_Step_L1();
    }
    PuzaLogger::Instance()->PutString("\tM-Step Finished."+to_string<int>(ITER,std::dec));
    Likelihood();
    PuzaLogger::Instance()->PutString("\tLabel Switch:" + to_string<int>(switch_label,std::dec));
    PuzaLogger::Instance()->PutString("\tLikelihood:" + to_string<double>(lowerbound,std::dec));
    if((lowerbound < old_lowerbound) && ( ITER != 0)){
      break;
    }
    old_lowerbound = lowerbound;

    if (ITER % 50 == 0){
      SaveModel();
    }

    if (ITER>=500){
      break;
    }

    ITER ++;
  }
  PuzaLogger::Instance()->PutString("Batch Learning Finished.");
}

void GeoMFOnline::Prediction(){
}
 
double GeoMFOnline::Likelihood(){
  double result = 0.0;
  for(unsigned int d = 0; d < TM_DOCS.size(); d++){
    int k = doc_topic_z[d];
    int region = doc_geo_stamp[d];
    int user = doc_user_stamp[d];
    TermList current_list = TM_DOCS[d];
    int term_count = current_list.size();
    
    for(int j =0; j < PuzaDEF::Instance()->TOPIC_NUM;j++){
      theta_norm_buffer[j] = theta_0[j] + theta_geo[region][j] + theta_user[user][j];
    }
    double theta_norm = log_sum_array(theta_norm_buffer,PuzaDEF::Instance()->TOPIC_NUM);
    result = result + theta_0[k] + theta_user[user][k] + theta_geo[region][k] - theta_norm;
    for (int j=0;j < term_count; j++){
      int term_id = current_list[j].term_id;
      int count = current_list[j].term_stat;
      result = result + count * (phi_0[term_id] + phi_geo[region][term_id] + pi[k][term_id] - phi_norm[region][k]);
    }      
  }
  lowerbound = result;
  return lowerbound;
}

int GeoMFOnline::ReadDOCS(){
  int MAX_INT = 0;
  int c = 0;
  string temp;
  N = 0;
  if(PuzaDEF::Instance()->input_file_name.empty()){
    cout << "Please give input file name." << endl;
    exit(0);
  }
  PuzaDEF::Instance()->InputFile.open(PuzaDEF::Instance()->input_file_name.c_str());
  if(!PuzaDEF::Instance()->InputFile){
    cout << "Can't open the file." << endl;
    exit(0);
  }
  PuzaDEF::Instance()->data_ids.clear();
  string original_id;
  string temp_geo_stamp;
  string temp_user_stamp;
  vector<string> buffer;
  while(!PuzaDEF::Instance()->InputFile.eof()){
    getline(PuzaDEF::Instance()->InputFile,temp,'\n');
    std::istringstream iss(temp);
    // get the doc id
    getline(iss,temp,'\t');
    original_id = temp;
    // get geo                                                                                                                                 
    getline(iss,temp,'\t');
    temp_geo_stamp = temp;
    // get user
    getline(iss,temp,'\t');
    temp_user_stamp = temp;
    // get the doc body
    getline(iss,temp,'\n');
    std::istringstream tempiss(temp);
    vector<string> tokens;
    copy(istream_iterator<string>(tempiss), istream_iterator<string>(), back_inserter<vector<string> >(tokens));
    if(tokens.size()<1){
      continue;
    }

    int now_id = PuzaDEF::Instance()->data_ids.size();
    PuzaDEF::Instance()->data_ids[now_id] = original_id;
    map<string,int>::iterator geo_iter = geo_reverse_mapping.find(temp_geo_stamp);
    int geo_id = -1;
    int user_id = -1;
    if(geo_iter != geo_reverse_mapping.end()){
      // id found
      geo_id = (*geo_iter).second;
      doc_geo_stamp.push_back(geo_id);
    }
    else{
      geo_id = geo_reverse_mapping.size();
      geo_reverse_mapping[temp_geo_stamp] = geo_id;
      geo_mapping[geo_id] = temp_geo_stamp;
      doc_geo_stamp.push_back(geo_id);
    }

    map<string,int>::iterator user_iter = user_reverse_mapping.find(temp_user_stamp);
    if(user_iter != user_reverse_mapping.end()){
      // id found
      user_id = (*user_iter).second;
      doc_user_stamp.push_back(user_id);
    }
    else{
      user_id = user_reverse_mapping.size();
      user_reverse_mapping[temp_user_stamp] = user_id;
      user_mapping[user_id] = temp_user_stamp;
      doc_user_stamp.push_back(user_id);
    }

    // check user geo dist
    TermList assignList;
    int temp_n = 0;
    // update randomized parameters
    doc_topic_z[c] = (int)random_uniform_distribution(0, PuzaDEF::Instance()->TOPIC_NUM);
    int k = doc_topic_z[c];
    for (vector<string>::iterator iter = tokens.begin(); iter < tokens.end(); iter++){
      int word_id;
      int word_count;
      std::istringstream valueiss((*iter));
      getline(valueiss,temp,':');
      from_string<int>(word_id,temp,std::dec);
      getline(valueiss,temp);  // get count
      from_string<int>(word_count,temp,std::dec);
      TermItem newAssign;
      newAssign.term_id = word_id;
      newAssign.term_stat = word_count;
      assignList.push_back(newAssign);
      phi_geo[geo_id][word_id] = 0.0;
      N = N + word_count;
      temp_n = temp_n + word_count;
      phi_0[word_id] = phi_0[word_id] + word_count;
    }
    if((int)assignList.size() > MAX_INT)
      MAX_INT = assignList.size();
    TM_DOCS.push_back(assignList);
    doc_n.push_back(temp_n);
    theta_0[k] = theta_0[k] + 1;
    d_k[k] = d_k[k] + 1;
    d_r_k[geo_id][k] = d_r_k[geo_id][k] + 1;
    d_r[geo_id] = d_r[geo_id] + 1;
    d_u[user_id] = d_u[user_id] + 1;
    d_u_k[user_id][k] = d_u_k[user_id][k] + 1;
    c = c + 1;
  }
  PuzaDEF::Instance()->InputFile.close();
  return MAX_INT;
}

int GeoMFOnline::GetDocuments(int choice){
  ReadDOCS();
  for(int i=0; i < PuzaDEF::Instance()->TERM_NUM; i++){
    phi_0[i] = log((phi_0[i] + 1.0)/(N+PuzaDEF::Instance()->TERM_NUM));
    phi_norm_buffer[i] = phi_0[i];
  }
  double phi_norm_temp = log_sum_array(phi_norm_buffer,PuzaDEF::Instance()->TERM_NUM);

  for(int r=0; r < PuzaDEF::Instance()->GEO_REGION_NUM; r++){
    for(int k=0; k < PuzaDEF::Instance()->TOPIC_NUM; k++){
      phi_norm[r][k] = phi_norm_temp;
    }
  }

  // some initialization
  for(int k=0; k < PuzaDEF::Instance()->TOPIC_NUM; k ++){
    theta_0[k] = log((theta_0[k] + 1.0)/(doc_n.size()+PuzaDEF::Instance()->TOPIC_NUM));
  }
  return 0;
}
#endif
